package com.rj;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.dtflys.forest.springboot.annotation.ForestScan;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rj.gpdata.client.ApiFinanceClient;
import com.rj.gpdata.client.ApiKlineClient;
import com.rj.gpdata.client.ProxyIpClient;
import com.rj.gpdata.domain.DataHandlerService;
import com.rj.gpdata.domain.query.*;
import com.rj.core.domain.BeanDomain2;
import com.rj.framework.biz.User;
import com.rj.framework.biz.UserMapper;
import com.rj.framework.component.tech.mybatis.DataBaseRequest;
import com.rj.framework.component.tech.mybatis.DataBaseResponse;
import com.rj.framework.component.tech.mybatis.DatabaseComponent;
import com.rj.framework.component.tech.mybatis.OperationType;
import com.rj.framework.context.Context;
import com.rj.framework.context.DefaultGlobalContext;
import com.rj.framework.context.GenericContext;
import com.rj.framework.context.UserContext;
import com.rj.gpdata.domain.res.JJcfDataRes;
import com.rj.gpdata.domain.res.bk.BkdataRes;
import com.rj.gpdata.domain.res.bk.Result;
import com.rj.gpdata.domain.res.ips.Ip;
import com.rj.gpdata.domain.res.ips.IpRes;
import com.rj.gpdata.domain.res.finance.DataResult;
import com.rj.gpdata.domain.res.finance.MainFinaDataResponse;
import com.rj.gpdata.domain.res.kline.KlineData;
import com.rj.gpdata.domain.res.kline.StockKlineResponse;
import com.rj.util.JsonUtil;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.net.SocketTimeoutException;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;

/**
 * 控制器测试
 *
 * @author YFX_RANLUBO
 * @date 2024/09/17 07:46
 **/
@RestController
@RequiredArgsConstructor
@Slf4j
public class TestController {
    private final ObjectMapper mapper;
    private final ApiKlineClient apiClient;
    private final ApiFinanceClient apiFinanceClient;
    private  final DataHandlerService dataHandlerService;
    private final ProxyIpClient proxyIpClient;
    private final static LinkedBlockingDeque<Ip> queue=new LinkedBlockingDeque();

   private void queryMainData(BiConsumer<String,String> consumer,boolean secidFlag,String where){
       dataHandlerService.queryMainCodeData("dfc_main_data m","f12 code,f14 name,f13 market",where,(rs)-> {
           String code = rs.getString("CODE");
           String market = rs.getString("MARKET");
           String secid = market + "." + code;
           String secuCode = code + "." + ("0".equals(market) ? "SZ" : "SH");
           consumer.accept(secuCode,secidFlag?secid:secuCode);
       });

   }


     /**
     * 同步日K线数据(全量)
     */
    public void mainSynKlineData(){
        if(queue.size() == 0){
            //获取代理IP
            IpRes ipRes=proxyIpClient.getProxyIp(10);
            ipRes.getList().forEach(ip->{
                queue.addLast(ip);
            });
            System.out.println(ipRes);
        }
        ExecutorService executorService=new ScheduledThreadPoolExecutor(30);
        ConcurrentLinkedDeque<Future> futures=new ConcurrentLinkedDeque<>();
        dataHandlerService.queryMainCodeData("dfc_main_data m","f12 code,f14 name,f13 market","not EXISTS (SELECT 1 FROM `syn_log` where SECURITY_CODE=m.f12  and log_type=2)",(rs)->{
            String code =rs.getString("CODE");
            String market =rs.getString("MARKET");
            String secid =market+"."+code;
            String secuCode =code+"."+("0".equals(market)?"SZ":"SH");
            futures.addLast(executorService.submit(()->{
                try {
                    Ip ip =getProxyIp();
                    kline(code, secid, null, false,ip);
                    queue.addLast(ip);
                }catch (Exception e){
                    e.printStackTrace();
                    if(queue.size() == 0) {
                        synchronized (TestController.class) {
                            if (queue.size() == 0) {
                                //获取代理IP
                                IpRes ipRes = proxyIpClient.getProxyIp(10);
                                ipRes.getList().forEach(ip -> {
                                    queue.addLast(ip);
                                });
                                System.out.println(ipRes);
                            }
                        }
                    }
                }


            }));
        });
        while (!futures.isEmpty()){
            Future future=futures.pollFirst();
            if(future!=null && !future.isDone()){
                try {
                    //等待完成
                    future.get();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

    }
    /**
     * 日K线数据
     * @param secid "0.000001"
     * @param lmt  最近的N条数据。
     */
   private void kline(String securityCode,String secid,Integer lmt,boolean findTotal,Ip ip){
       QueryParam param=new QueryParam();
       Long time=new Date().getTime();
       param.setCb(String.format(param.getCb(),time,time));
       param.setSecid(secid);
       if(lmt != null){
           param.setLmt(lmt);
       }
       if(findTotal){
           param.setLmt(1);
       }
       String   jsonp;
       if(ip != null){
           jsonp= apiClient.getDayData(param,time,ip.getSever(), ip.getPort());
       }else{
           jsonp= apiClient.getDayData(param,time,null, null);
       }
       String json=jsonp.substring(param.getCb().length()+1,jsonp.length()-2);
       StockKlineResponse res= JsonUtil.toObject(json, StockKlineResponse.class);
       KlineData data = res.getData();
       AtomicInteger atomicInteger=new AtomicInteger(data.getTotal()) ;
       dataHandlerService.queryLogData(securityCode,2,atomicInteger);
       if(data != null){
           if(findTotal){
               //差异数
               Integer cys=atomicInteger.get();
               if(cys== 0){
                   //没有差异不新增数据
                   return;
               }else if (cys>1){
                   //差别大于一条重新查询
                   kline(securityCode,secid,cys,false,ip);
                   return;
               }
               //差异一条继续执行
       }
           data.convertFields2ToKlineItems(param.getFields2(),securityCode);
           dataHandlerService.saveData(data.getKlineItems(),"dfc_kline_data_"+securityCode.substring(0,3));
           dataHandlerService.updateLogData(securityCode,2,data.getTotal());
       }
    }
    private Ip getProxyIp(){

        Ip proxyIp= queue.poll();
        while (proxyIp == null){
            try {
                Thread.sleep(1000);
                proxyIp=queue.poll();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        return proxyIp;
    }
    /**
     * 获取场内基金成分前10
     */
    private void queryJJCfClist(String securityCode) {
       String text=  apiClient.FundArchivesDatas(securityCode);
        JJcfDataRes res=new JJcfDataRes();
        res.setText(text);
        res.handleData(securityCode);
        dataHandlerService.saveData(res.getDatas(),"dfc_kline_data_jj_cf");
    }
    /**
     * 获取场内基金当日数据
     */
    private void queryJJClist(AtomicInteger page) {
        QueryJJlbParam param = new QueryJJlbParam();
        param.setPz(100);
        param.setPn(page.get());
        Long time = new Date().getTime();
        param.setCb(String.format(param.getCb(), time, time));
        String jsonp = apiClient.getClistData(param, time);
        String json = jsonp.substring(param.getCb().length() + 1, jsonp.length() - 2);
        System.out.println(json);
        StockKlineResponse res = JsonUtil.toObject(json, StockKlineResponse.class);
        KlineData data = res.getData();
        if (data != null) {
            try {
                dataHandlerService.saveData(data.getDiff(), "dfc_kline_data_jj");
                if(data.getTotal()>param.getPz()*param.getPn()){
                    page.incrementAndGet();
                    Thread.sleep(5000);
                    queryJJClist(page);
                }else {
                    dataHandlerService.updateLogData("dfc_kline_data_jj", 3, data.getTotal());
                }
            } catch (Exception e) {
                log.error("queryJJClist error",e);
            }

        }
    }
    /**
     * 主股票列表
     */
    private void queryClist(AtomicInteger page){
        QueryClistParam param= new QueryClistParam();
        param.setPz(100);
        param.setPn(page.get());
        Long time=new Date().getTime();
        param.setCb(String.format(param.getCb(),time,time));
        //Ip proxyIp=getProxyIp();
        //String jsonp = apiClient.getClistData(param,proxyIp.getSever(), proxyIp.getPort());
        String jsonp = apiClient.getClistData(param,null, null);
        String json=jsonp.substring(param.getCb().length()+1,jsonp.length()-2);
        System.out.println(json);
        StockKlineResponse res= JsonUtil.toObject(json, StockKlineResponse.class);
        KlineData data = res.getData();
        if(data != null){
            try {
                dataHandlerService.saveData(data.getDiff(),"dfc_main_data");
            } catch (Exception e) {
               e.fillInStackTrace();
            }

            if(data.getTotal()>param.getPz()*param.getPn()){
                page.incrementAndGet();
                queryClist(page);
            }else {
                dataHandlerService.updateLogData("main_data",1,data.getTotal());
            }

        }
    }
    /**
     * 主财务数据
     */
    private void mainFinaData(String securityCode,String secuCode,Integer pageSize,boolean findTotal){

        QueryMainFinaData param= new QueryMainFinaData();
        param.setFilter(secuCode);
        if(pageSize != null){
            param.setPs(pageSize);
        }
        if(findTotal){
            param.setPs(1);
        }
        String json = apiFinanceClient.get(param);
        MainFinaDataResponse res =  JsonUtil.toObject(json, MainFinaDataResponse.class);
        DataResult dataResult= res.getResult();
        if(dataResult != null){
            if(findTotal){
                AtomicInteger atomicInteger=new AtomicInteger(dataResult.getCount()) ;
                dataHandlerService.queryLogData(securityCode,1,atomicInteger);
                //差异数
                Integer cys=atomicInteger.get();
                if(cys== 0){
                    //没有差异不新增数据
                    return;
                }else if (cys>1){
                    //差别大于一条重新查询
                    mainFinaData(securityCode,secuCode,cys,false);
                    return;
                }
                //差异一条继续执行
            }
            List<Map> data = res.getResult().getData();
            dataHandlerService.saveData(data,"dfc_mian_fina_data");
            dataHandlerService.updateLogData(securityCode,1,dataResult.getCount());
            return;
        }
        System.out.println("dfc_mian_fina_data 完成");

    }


    /**
     * 获取板块概念数据
     */
    private void queryBKClist(String securityCode) {
        QueryGlbkParam param = new QueryGlbkParam();
        param.setFilter(securityCode);
        BkdataRes res=  apiClient.getGlbkData(param);
        if(res != null && res.isSuccess() ){
         Result result =  res.getResult();
         if(result != null){
             List<Map> data = result.getData();
             dataHandlerService.saveData(data,"dfc_glbk_data");
             dataHandlerService.updateLogData(securityCode,4,data.size());
         }
        }

    }

   //@Scheduled(cron = "0 0 21 * * ?")
    @PostConstruct
    private void init(){
        ///关键分析不用把所有股票数据下载
       //同步当日主数据
       dataHandlerService.updateData("dfc_main_data","SYN_ZT='Y'","SYN_ZT='N'");
       queryClist(new AtomicInteger(1));
       //同步当日基金数据
       dataHandlerService.updateData("dfc_kline_data_jj","syn_time=now(),syn_zt='Y'","syn_zt='N'");
       queryJJClist(new AtomicInteger(1));

       //同步当日基金成分
       /*dataHandlerService.queryMainCodeData("dfc_kline_data_jj m",
               "f12 code",
               (rs)-> {
           queryJJCfClist(rs.getString("CODE"));
       });*/
       //加载板块数据
       /*queryMainData((code,sec)->{
           queryBKClist(code);
       },false,"rq='2025-09-02'");*/
       //单独提取个股日数据
       // kline("000034","0.000034",null,false, null);

   }
    @GetMapping("/beanTest")
    public BeanDomain2 beanTest(@Validated @RequestBody BeanDomain2 beanDomain2) throws JsonProcessingException {
        return beanDomain2;
    }

    @GetMapping("/database")
    public DataBaseResponse<User> database() throws JsonProcessingException {
        DatabaseComponent databaseComponent = new DatabaseComponent();
        Context<?> context = new GenericContext<>(new DefaultGlobalContext(new UserContext() {
            @Override
            public String getUserId() {
                return "1";
            }

            @Override
            public String getTenantId() {
                return "2";
            }
        }));
        DataBaseRequest<User> request = new DataBaseRequest<>();
        request.setMapperClass(UserMapper.class);
        request.setOperationType(OperationType.FIND_ALL);
        LambdaQueryWrapper<User> wrapper =  Wrappers.lambdaQuery();
        request.setWrapper(wrapper.eq(User::getId, "1937804233183072257"));
        return databaseComponent.execute(request, context);
    }

    @SpringBootApplication
    @Configuration
    @ForestScan(basePackages  = "com.gpdata.client")
    public static class DemoApplication {


        public static void main(String[] args) {

            SpringApplication.run(DemoApplication.class, args);
        }

    }
}
